
import type { Event } from './Event';

// #region EventTarget
export interface IEventTarget {
  // TODO:
  //emitter: EventEmitter;

  // on: (
  //   type: string,
  //   listener: EventListenerOrEventListenerObject | ((...args: any[]) => void),
  //   options?: boolean | AddEventListenerOptions,
  // ) => void;
  addEventListener: (
    type: string,
    listener: EventListenerOrEventListenerObject,
    options?: boolean | AddEventListenerOptions,
  ) => void;

  // off: (
  //   type: string,
  //   listener: EventListenerOrEventListenerObject | ((...args: any[]) => void),
  //   options?: boolean | AddEventListenerOptions,
  // ) => void;
  removeEventListener: (
    type: string,
    listener: EventListenerOrEventListenerObject,
    options?: boolean | AddEventListenerOptions,
  ) => void;
  // removeAllEventListeners: () => void;

  /**
   * @param skipPropagate - The default value is `false`. If true, the event is only triggered globally (note that the global is not the object itself), skipping the event propagation process. In addition, if the object has been removed from the global, the event is only triggered on the object itself.
   * @param dispatchToSelf - The default value is `false`. If true, the event will be triggered on the object itself.
   *
   * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent
   */
  dispatchEvent: <T extends Event>(
    e: T,
    skipPropagate?: boolean,
    dispatchToSelf?: boolean,
  ) => boolean;

  // emit: (eventName: string, object: object) => void;
}


// #region Node
export interface INode extends IEventTarget {
  shadow: boolean;
  /**
   * Returns node's node document's document base URL.
   */
  readonly baseURI: string;
  /**
   * Returns the children.
   */
  readonly childNodes: IChildNode[];
  /**
   * Returns the first child.
   */
  readonly firstChild: IChildNode | null;
  /**
   * Returns true if node is connected and false otherwise.
   */
  isConnected: boolean;
  /**
   * Returns the last child.
   */
  readonly lastChild: IChildNode | null;

  /**
   * Returns the next sibling.
   */
  readonly nextSibling: IChildNode | null;
  /**
   * Returns a string appropriate for the type of node.
   */
  readonly nodeName: string;
  /**
   * Returns the type of node.
   */
  readonly nodeType: number;
  nodeValue: string | null;
  /**
   * Returns the node document. Returns null for documents.
   */
  ownerDocument: IDocument | null;
  /**
   * Returns the parent element.
   */
  readonly parentElement: IElement | null;
  /**
   * Returns the parent.
   */
  parentNode: (INode & IParentNode) | null;
  /**
   * Returns the previous sibling.
   */
  readonly previousSibling: IChildNode | null;
  textContent: string | null;
  appendChild: <T extends INode>(newChild: T, index?: number) => T;
  /**
   * Returns a copy of node. If deep is true, the copy also includes the node's descendants.
   */
  cloneNode: (deep?: boolean) => INode;
  /**
   * Returns a bitmask indicating the position of other relative to node.
   */
  compareDocumentPosition: (other: INode) => number;
  /**
   * Returns true if other is an inclusive descendant of node, and false otherwise.
   */
  contains: (other: INode | null) => boolean;
  /**
   * Returns node's root.
   */
  getRootNode: (options?: GetRootNodeOptions) => INode;
  /**
   * Returns node's ancestor.
   */
  getAncestor: (n: number) => INode | null;
  /**
   * iterate current node and its descendants
   * @param callback - callback to execute for each node, return false to break
   */
  forEach: (callback: (o: INode) => void | boolean) => void;
  /**
   * Returns whether node has children.
   */
  hasChildNodes: () => boolean;
  insertBefore: <T extends INode>(newChild: T, refChild: INode | null) => T;
  isDefaultNamespace: (namespace: string | null) => boolean;
  /**
   * Returns whether node and otherNode have the same properties.
   */
  isEqualNode: (otherNode: INode | null) => boolean;
  isSameNode: (otherNode: INode | null) => boolean;
  lookupNamespaceURI: (prefix: string | null) => string | null;
  lookupPrefix: (namespace: string | null) => string | null;
  /**
   * Removes empty exclusive Text nodes and concatenates the data of remaining contiguous exclusive Text nodes into the first of their nodes.
   */
  normalize: () => void;
  removeChild: <T extends INode>(oldChild: T) => T;
  replaceChild: <T extends INode>(newChild: INode, oldChild: T) => T;

  /**
   * Destroy itself.
   */
  destroy: () => void;
}